using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AtDevice
{
    class PhoneBook : IPhoneBook
    {
        private AtDevice _device;
        private string _name;
        private int _storageSize;
        private int _usedSize;

        public PhoneBook(AtDevice device, string name)
        {
            _device = device;
            _name = name;
            _storageSize = GetStorageSize();
            _usedSize = GetUsedStorage();
            Console.WriteLine("Storage {0} with size {1}/{2}", name, _usedSize, _storageSize);
        }

        public string GetName()
        {
            return _name;
        }

        /// <summary>
        /// Set the phonebook storage to current phonebook before doing any operations to items in it. 
        /// </summary>
        private void SelectStorage()
        {
            _device.ExecuteCommand(new AtCommand("CPBS").AppendString(GetName()));
        }

        public List<PhoneBookEntry> GetEntries()
        {
            List<PhoneBookEntry> entries = new List<PhoneBookEntry>();

            if(_usedSize > 0)
            {
                SelectStorage();
                AtResponse response = _device.ExecuteCommand(new AtCommand("CPBR")
                                                                        .AppendInt(1)
                                                                        .AppendInt(Math.Min(_storageSize, _usedSize)));
    
                foreach (var item in response.Items)
                {
                    entries.Add(new PhoneBookEntry() {
                        Index = item.GetInt(0),
                        MobileNumber = item.GetString(1),
                        Name = item.GetString(3)
                    });
                }
            }

            return entries;
        }

        public int GetUsedStorage()
        {
            try {
                SelectStorage();
                AtResponse response = _device.ExecuteCommand(new AtCommand("CPBS").Request());
                return response.GetInt(1);
            } catch(AtException)
            {
                return 0;
            }
        }

        public int GetStorageSize()
        {
            try {
                SelectStorage();
                AtResponse response = _device.ExecuteCommand(new AtCommand("CPBS").Request());
                return response.GetInt(2);
            } catch(AtException)
            {
                return 0;
            }
        }

        public void AddEntry(PhoneBookEntry entry)
        {
            // 3GPP TS 27.007 8.14    Write phonebook entry +CPBW
            //+CPBW=[<index>][,<number>[,<type>[,<text>[,<group>
            //          [,<adnumber>[,<adtype>[,<secondtext>[,<email>
            //          [,<sip_uri>[,<tel_uri>[,<hidden>]]]]]]]]]]]

            SelectStorage();
            _device.ExecuteCommand(new AtCommand("CPBW")
                                            .AppendInt(entry.Index)
                                            .AppendString(entry.MobileNumber)
                                            .AppendInt(145)
                                            .AppendString(entry.Name)
                                            .AppendString("") // group
                                            .AppendString(entry.OfficeNumber)
                                            .AppendInt(145)
                                            .AppendString(entry.Remarks)
                                            .AppendString(entry.Email)
                                            .AppendString("naanaa")
                                            .AppendString(entry.HomeNumber));
        }
        
        public void UpdateEntry(PhoneBookEntry entry)
        {
            AddEntry(entry);
        }

        public void DeleteEntry(PhoneBookEntry entry)
        {
            SelectStorage();
            // delete by writing empty entry to the memory location
            _device.ExecuteCommand(new AtCommand("CPBW")
                                            .AppendInt(entry.Index));
        }

        public bool IsIndexFree(int index)
        {
            try
            {
                // Try to read the memory location and get an error if it's empty
                _device.ExecuteCommand(new AtCommand("CPBR").AppendInt(index));
                return false;
            }
            catch (AtException)
            {
                return true;
            }
        }

        public int GetFreeIndex()
        {
            SelectStorage();
            int index = 0;
            int maxValue = _storageSize;
            while (++index < maxValue)
            {
                if(IsIndexFree(index))
                    return index;
            }

            return 0;
        }
    }
}
